package de.hauschild.orbitvm.controller.impl;

import java.awt.Color;

import de.hauschild.orbitvm.controller.Controller;
import de.hauschild.orbitvm.visualization.VMFrame;
import de.hauschild.orbitvm.vm.VM;
import de.hauschild.orbitvm.vm.VMException;

/**
 * An abstract implementation of {@link Controller} providing basic functionality of the following points.
 * <ul>
 * <li>virtual machine iteration</li>
 * <li>visualization of basic objects</li>
 * </ul>
 * 
 * @since 1.0.0
 * @author Klaus Hauschild
 */
public abstract class AbstractController implements Controller {

  protected static final String DOUBLE_FORMAT_STRING = "%.2f";
  protected static final double ONE_KILOMETER = 1000.0;

  private final VM vm;
  private final VMFrame vmFrame;
  private int iteration;

  /**
   * Instantiates a new {@link AbstractController}.
   * 
   * @param theVM
   *          the virtual machine
   * @param theVMFrame
   *          the virtual machine visualization frame
   */
  public AbstractController(final VM theVM, final VMFrame theVMFrame) {
    // store for later use
    vm = theVM;
    vmFrame = theVMFrame;
    // first iteration for vm initialization
    vm.iterate();
    // initialize controller
    initialize();
  }

  @Override
  public final void iterate() {
    try {
      Thread.sleep(0);
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }
    beforeIteration();
    try {
      iteration = vm.iterate();
    } catch (final VMException vme) {
      updateUI();
      throw vme;
    }
    updateUI();
    afterIteration();
  }

  /**
   * After iteration.
   */
  protected abstract void afterIteration();

  /**
   * Before iteration.
   */
  protected abstract void beforeIteration();

  protected int getIteration() {
    return iteration;
  }

  /**
   * Initialize.
   */
  protected abstract void initialize();

  /**
   * Gets the virtual machine.
   * 
   * @return the virtual machine
   */
  protected VM vm() {
    return vm;
  }

  /**
   * Gets the virtual machine visualization frame.
   * 
   * @return the virtual machine visualization frame
   */
  protected VMFrame vmFrame() {
    return vmFrame;
  }

  /**
   * Update UI.
   */
  private void updateUI() {
    vmFrame.getIterationLabel().setText(String.format("%ds", iteration));
    vmFrame.getScoreLabel().setText(String.format(DOUBLE_FORMAT_STRING, vm.getScore()));
    vmFrame.getRemainingFuelLabel().setText(String.format(DOUBLE_FORMAT_STRING, vm.getRemainingFuel()));
    vmFrame.getEarthDistanceLabel().setText(String.format(DOUBLE_FORMAT_STRING, vm.getDistanceToEarth()));

    final Double x = vm.getSatellitePosition().getX() / VMFrame.SIZE_FACTOR + VMFrame.IMAGE_SIZE / 2;
    final Double y = -vm.getSatellitePosition().getY() / VMFrame.SIZE_FACTOR + VMFrame.IMAGE_SIZE / 2;
    vmFrame.startDraw();
    vmFrame.drawPixel(x.intValue(), y.intValue(), Color.WHITE);
  }

}
